#pragma once
#include<iostream>
#include"pthread.hpp"
#include<vector>
#include"log.hpp"
#include"mutex.hpp"
#include"block_queue.hpp"

namespace ly{
    //默认个数
    #define DEFAULT_NUM_THREADS 4
    struct Data{
        Data(thread_func f=nullptr,void *d=nullptr):func(f),data(d){}
        ~Data(){}
        thread_func func;
        void *data;
    };
    template<class T>
    class PthreadPool{
        private:
        void* HandlerTask(void *arg){
            while(true){
                Data t=queue->pop();
                //T d=*(T*)arg;
                if(t.func==nullptr){
                    break;
                }
                t.func(t.data);
                if(is_running==false){
                    break;
                }
            }
            return nullptr;
        }
        PthreadPool(int num=DEFAULT_NUM_THREADS,
                ly::BlockQueue<Data>* q=nullptr):num_threads(num),queue(q)
            {
                is_running=false;
                for(int i=0;i<num_threads;i++){
                    //std::bind(&ThreadPool::HandlerTask, this)
                    //threads.push_back(ly::pthread<int>(std::bind(&PthreadPool::HandlerTask, this,data)));
                    threads.push_back(ly::pthread<int>([this](void* arg)->void*{
                        this->HandlerTask(arg);
                        return nullptr;
                    }));
                    LOG(ly::LogLevel::DEBUG)<<"创建了一个线程";
                }
            }
        public:
            PthreadPool(PthreadPool& t)=delete;
            PthreadPool& operator=(PthreadPool& t)=delete;
            // PthreadPool(int num=DEFAULT_NUM_THREADS,
            //     ly::BlockQueue<Data>* q=nullptr):num_threads(num),queue(q)
            // {
            //     is_running=false;
            //     for(int i=0;i<num_threads;i++){
            //         //std::bind(&ThreadPool::HandlerTask, this)
            //         //threads.push_back(ly::pthread<int>(std::bind(&PthreadPool::HandlerTask, this,data)));
            //         threads.push_back(ly::pthread<int>([this](void* arg)->void*{
            //             this->HandlerTask(arg);
            //             return nullptr;
            //         }));
            //         LOG(ly::LogLevel::DEBUG)<<"创建了一个线程";
            //     }
            // }
            static PthreadPool<T>* GetInstance(){
                if(instance==nullptr){
                    ly::LockGuard Lock(instance_mutex);
                    if(instance==nullptr){
                        instance=new PthreadPool<T>();
                    }
                }
                return instance;
            }
            void set_num_threads(int num){
                num_threads=num;
            }
            ~PthreadPool(){
                if(is_running){
                    stop();
                }
            }
            void start(){
                if(is_running) return;
                is_running=true;
                if(queue==nullptr){
                    LOG(ly::LogLevel::ERROR)<<"队列为空";
                    return;
                }
                for(int i=0;i<threads.size();i++){
                    threads[i].start();
                }
                LOG(ly::LogLevel::DEBUG)<<"启动线程池";
            }
            void stop(){
                LOG(ly::LogLevel::DEBUG)<<"停止线程池";
                if(!is_running) return;
                is_running=false;queue->set_running(false);
                while(queue->GetConsumerWaitNum()>0){
                    queue->wake_all();
                    //sleep(1);
                }
                for(int i=0;i<threads.size();i++){
                        if(threads[i].is_running()){
                            LOG(ly::LogLevel::DEBUG)<<"等待线程"<<i<<"退出";
                            threads[i].join();
                        }
                        LOG(ly::LogLevel::DEBUG)<<"退出了一个线程";
                    }
                LOG(ly::LogLevel::DEBUG)<<"线程池停止";
            }
            void push(thread_func f,void *data=nullptr){
                queue->push(Data(f,data));
            }
            T pop(){
                if(queue==nullptr){
                    LOG(ly::LogLevel::ERROR)<<"队列为空";
                    return nullptr;
                }
                return queue->pop();
            }
            //设置容器
            void set_queue(ly::BlockQueue<Data>* q){
                if(queue!=nullptr){
                    LOG(ly::LogLevel::ERROR)<<"队列已存在";
                    return;
                }
                queue=q;
            }
        private:
            int num_threads;
            ly::Mutex mutex;
            ly::BlockQueue<Data>* queue;
            std::vector<ly::pthread<int>> threads;
            bool is_running;
            //单例模式
            static PthreadPool<T>* instance;
            static ly::Mutex instance_mutex;
    };
    template<class T>
    PthreadPool<T>* PthreadPool<T>::instance=nullptr;
    template<class T>
    ly::Mutex PthreadPool<T>::instance_mutex;
}